package com.thz.system.service.cos.impl;

import cn.hutool.core.util.IdUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.*;
import com.thz.common.enums.ErrorCode;
import com.thz.common.exception.CosException;
import com.thz.common.utils.FileUtils;
import com.thz.system.config.CosConfig;
import com.thz.system.service.cos.ICosFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;

/**
 * COS文件服务实现类
 * 
 * @author THZ
 * @date 2025
 */
@Slf4j
@Service
public class CosFileServiceImpl implements ICosFileService {
    
    @Autowired
    private COSClient cosClient;
    
    @Autowired
    private CosConfig cosConfig;
    
    @Override
    public String uploadFile(MultipartFile file, String prefix) {
        if (file == null || file.isEmpty()) {
            throw new CosException(ErrorCode.FILE_EMPTY);
        }
        
        try {
            String originalFilename = file.getOriginalFilename();
            String fileName = generateFileName(originalFilename);
            String key = prefix + fileName;
            
            InputStream inputStream = file.getInputStream();
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(file.getSize());
            metadata.setContentType(file.getContentType());
            
            return uploadToCos(inputStream, key, metadata);
        } catch (IOException e) {
            log.error("上传文件到COS失败", e);
            throw new CosException(ErrorCode.FILE_UPLOAD_FAILED, "文件读取失败", e);
        }
    }
    
    @Override
    public String uploadFile(File localFile, String prefix) {
        if (localFile == null || !localFile.exists()) {
            throw new CosException(ErrorCode.FILE_NOT_FOUND);
        }
        
        try {
            String fileName = generateFileName(localFile.getName());
            String key = prefix + fileName;
            
            FileInputStream inputStream = new FileInputStream(localFile);
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(localFile.length());
            
            // 设置Content-Type，让浏览器能正确识别文件类型
            String contentType = getContentType(localFile.getName());
            metadata.setContentType(contentType);
            
            // 设置Content-Disposition为inline，让浏览器预览而不是下载
            metadata.setContentDisposition("inline");
            
            return uploadToCos(inputStream, key, metadata);
        } catch (FileNotFoundException e) {
            log.error("本地文件不存在: {}", localFile.getAbsolutePath(), e);
            throw new CosException(ErrorCode.FILE_NOT_FOUND, "本地文件不存在", e);
        }
    }
    
    @Override
    public String uploadFile(InputStream inputStream, String fileName, String prefix) {
        String newFileName = generateFileName(fileName);
        String key = prefix + newFileName;
        
        ObjectMetadata metadata = new ObjectMetadata();
        
        // 设置Content-Type
        String contentType = getContentType(fileName);
        metadata.setContentType(contentType);
        
        // 设置Content-Disposition为inline
        metadata.setContentDisposition("inline");
        
        return uploadToCos(inputStream, key, metadata);
    }
    
    /**
     * 上传到COS的核心方法
     */
    private String uploadToCos(InputStream inputStream, String key, ObjectMetadata metadata) {
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    cosConfig.getBucketName(), 
                    key, 
                    inputStream, 
                    metadata
            );
            
            PutObjectResult result = cosClient.putObject(putObjectRequest);
            log.info("文件上传成功 - key: {}, ETag: {}", key, result.getETag());
            
            return getFileUrl(key);
        } catch (CosServiceException e) {
            log.error("COS服务异常 - StatusCode: {}, ErrorCode: {}, ErrorMessage: {}", 
                    e.getStatusCode(), e.getErrorCode(), e.getErrorMessage(), e);
            throw new CosException(ErrorCode.FILE_UPLOAD_FAILED, 
                    "COS上传失败: " + e.getErrorMessage(), e);
        } catch (CosClientException e) {
            log.error("COS客户端异常", e);
            throw new CosException(ErrorCode.FILE_UPLOAD_FAILED, 
                    "COS客户端错误: " + e.getMessage(), e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                log.warn("关闭输入流失败", e);
            }
        }
    }
    
    @Override
    public void deleteFile(String fileUrl) {
        if (fileUrl == null || fileUrl.isEmpty()) {
            return;
        }
        
        try {
            String key = extractKeyFromUrl(fileUrl);
            cosClient.deleteObject(cosConfig.getBucketName(), key);
            log.info("文件删除成功 - key: {}", key);
        } catch (CosServiceException e) {
            log.error("COS删除文件失败 - StatusCode: {}, ErrorCode: {}, ErrorMessage: {}", 
                    e.getStatusCode(), e.getErrorCode(), e.getErrorMessage(), e);
            // 删除失败不抛出异常，只记录日志
        } catch (CosClientException e) {
            log.error("COS客户端删除文件异常", e);
        }
    }
    
    @Override
    public void downloadFile(String fileUrl, String localFilePath) {
        try {
            String key = extractKeyFromUrl(fileUrl);
            File localFile = new File(localFilePath);
            
            // 确保父目录存在
            if (!localFile.getParentFile().exists()) {
                localFile.getParentFile().mkdirs();
            }
            
            GetObjectRequest getObjectRequest = new GetObjectRequest(
                    cosConfig.getBucketName(), key);
            ObjectMetadata objectMetadata = cosClient.getObject(getObjectRequest, localFile);
            
            log.info("文件下载成功 - key: {}, 保存到: {}", key, localFilePath);
        } catch (CosServiceException e) {
            log.error("COS下载文件失败 - StatusCode: {}, ErrorCode: {}, ErrorMessage: {}", 
                    e.getStatusCode(), e.getErrorCode(), e.getErrorMessage(), e);
            throw new CosException(ErrorCode.FILE_DOWNLOAD_FAILED, 
                    "COS下载失败: " + e.getErrorMessage(), e);
        } catch (CosClientException e) {
            log.error("COS客户端下载文件异常", e);
            throw new CosException(ErrorCode.FILE_DOWNLOAD_FAILED, 
                    "COS客户端错误: " + e.getMessage(), e);
        }
    }
    
    @Override
    public InputStream downloadFile(String fileUrl) {
        try {
            String key = extractKeyFromUrl(fileUrl);
            GetObjectRequest getObjectRequest = new GetObjectRequest(
                    cosConfig.getBucketName(), key);
            COSObject cosObject = cosClient.getObject(getObjectRequest);
            return cosObject.getObjectContent();
        } catch (CosServiceException e) {
            log.error("COS获取文件流失败 - StatusCode: {}, ErrorCode: {}, ErrorMessage: {}", 
                    e.getStatusCode(), e.getErrorCode(), e.getErrorMessage(), e);
            throw new CosException(ErrorCode.FILE_DOWNLOAD_FAILED, 
                    "COS获取文件流失败: " + e.getErrorMessage(), e);
        } catch (CosClientException e) {
            log.error("COS客户端获取文件流异常", e);
            throw new CosException(ErrorCode.FILE_DOWNLOAD_FAILED, 
                    "COS客户端错误: " + e.getMessage(), e);
        }
    }
    
    @Override
    public String extractKeyFromUrl(String fileUrl) {
        if (fileUrl == null || fileUrl.isEmpty()) {
            return "";
        }
        
        // 如果已经是key，直接返回
        if (!fileUrl.startsWith("http://") && !fileUrl.startsWith("https://")) {
            return fileUrl;
        }
        
        // 从URL中提取key
        // 例如: https://bucket-123456.cos.ap-beijing.myqcloud.com/uploads/xxx.jpg
        // 或者: https://cdn.example.com/uploads/xxx.jpg
        try {
            String domain = cosConfig.getDomain();
            if (domain != null && fileUrl.startsWith(domain)) {
                // 使用配置的域名
                String key = fileUrl.substring(domain.length());
                if (key.startsWith("/")) {
                    key = key.substring(1);
                }
                return key;
            } else {
                // 从默认COS域名提取
                int index = fileUrl.indexOf(".myqcloud.com/");
                if (index > 0) {
                    return fileUrl.substring(index + ".myqcloud.com/".length());
                }
                
                // 如果都不匹配，尝试从域名后的第一个/开始提取
                int protocolIndex = fileUrl.indexOf("://");
                if (protocolIndex > 0) {
                    int pathIndex = fileUrl.indexOf("/", protocolIndex + 3);
                    if (pathIndex > 0) {
                        return fileUrl.substring(pathIndex + 1);
                    }
                }
            }
        } catch (Exception e) {
            log.warn("从URL提取key失败: {}", fileUrl, e);
        }
        
        return fileUrl;
    }
    
    @Override
    public boolean isCosUrl(String url) {
        if (url == null || url.isEmpty()) {
            return false;
        }
        
        // 判断是否是COS URL
        if (url.contains(".myqcloud.com")) {
            return true;
        }
        
        // 判断是否是配置的CDN域名
        String domain = cosConfig.getDomain();
        if (domain != null && url.startsWith(domain)) {
            return true;
        }
        
        return false;
    }
    
    @Override
    public String getFileUrl(String key) {
        String domain = cosConfig.getDomain();
        if (domain == null || domain.isEmpty()) {
            // 使用默认COS域名
            domain = "https://" + cosConfig.getBucketName() + 
                    ".cos." + cosConfig.getRegion() + ".myqcloud.com";
        }
        
        // 确保domain不以/结尾
        if (domain.endsWith("/")) {
            domain = domain.substring(0, domain.length() - 1);
        }
        
        // 规范化key：去除开头的 ./ 和 /
        if (key.startsWith("./")) {
            key = key.substring(2);
        } else if (key.startsWith("/")) {
            key = key.substring(1);
        }
        
        return domain + "/" + key;
    }
    
    @Override
    public InputStream downloadFileSafely(String fileUrl) {
        try {
            String key = extractKeyFromUrl(fileUrl);
            GetObjectRequest getObjectRequest = new GetObjectRequest(
                    cosConfig.getBucketName(), key);
            COSObject cosObject = cosClient.getObject(getObjectRequest);
            log.info("从COS安全下载文件成功: {}", key);
            return cosObject.getObjectContent();
        } catch (CosServiceException e) {
            log.warn("COS获取文件流失败(安全模式) - StatusCode: {}, ErrorCode: {}, ErrorMessage: {}", 
                    e.getStatusCode(), e.getErrorCode(), e.getErrorMessage());
            return null;
        } catch (CosClientException e) {
            log.warn("COS客户端获取文件流异常(安全模式): {}", e.getMessage());
            return null;
        } catch (Exception e) {
            log.warn("下载COS文件失败(安全模式): {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 生成唯一文件名
     */
    private String generateFileName(String originalFilename) {
        String extension = FileUtils.getFileExtension(originalFilename);
        return IdUtil.simpleUUID() + "." + extension;
    }
    
    /**
     * 根据文件名获取Content-Type
     */
    private String getContentType(String filename) {
        if (filename == null) {
            return "application/octet-stream";
        }
        
        String lowercaseFilename = filename.toLowerCase();
        
        // 图片类型
        if (lowercaseFilename.endsWith(".jpg") || lowercaseFilename.endsWith(".jpeg")) {
            return "image/jpeg";
        } else if (lowercaseFilename.endsWith(".png")) {
            return "image/png";
        } else if (lowercaseFilename.endsWith(".gif")) {
            return "image/gif";
        } else if (lowercaseFilename.endsWith(".svg")) {
            return "image/svg+xml";
        } else if (lowercaseFilename.endsWith(".webp")) {
            return "image/webp";
        } else if (lowercaseFilename.endsWith(".bmp")) {
            return "image/bmp";
        } else if (lowercaseFilename.endsWith(".ico")) {
            return "image/x-icon";
        }
        
        // 视频类型
        else if (lowercaseFilename.endsWith(".mp4")) {
            return "video/mp4";
        } else if (lowercaseFilename.endsWith(".avi")) {
            return "video/x-msvideo";
        } else if (lowercaseFilename.endsWith(".mov")) {
            return "video/quicktime";
        } else if (lowercaseFilename.endsWith(".wmv")) {
            return "video/x-ms-wmv";
        } else if (lowercaseFilename.endsWith(".flv")) {
            return "video/x-flv";
        } else if (lowercaseFilename.endsWith(".webm")) {
            return "video/webm";
        }
        
        // 文档类型
        else if (lowercaseFilename.endsWith(".pdf")) {
            return "application/pdf";
        } else if (lowercaseFilename.endsWith(".doc")) {
            return "application/msword";
        } else if (lowercaseFilename.endsWith(".docx")) {
            return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        } else if (lowercaseFilename.endsWith(".xls")) {
            return "application/vnd.ms-excel";
        } else if (lowercaseFilename.endsWith(".xlsx")) {
            return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        }
        
        // 默认
        return "application/octet-stream";
    }
}

